﻿using mozhi.smarterp.Finance.Accounts.Repository;
using mozhi.smarterp.Finance.Accounts.Services;
using mozhi.smarterp.Finance.Basedatas.Repository;
using mozhi.smarterp.Finance.Basedatas.Services;
using mozhi.smarterp.Finance.Finances.Repository;
using Mozhi.Abp.Domain.BasicData.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace mozhi.smarterp.Finance.Reports
{
    public class AccountBalanceReportAppService : ReportAppService, IAccountBalanceReportAppService
    {

        public AccountBalanceReportAppService(IAccountRepository accountRepository, IDimensionGroupValueRepository dimensionGroupValueRepository,
            ICurrencyRepository currencyRepository, ISettlementRepository settlementRepository, IAccountBalanceRepository accountBalanceRepository,
            AccountBalanceManager accountBalanceManager,DimensionGroupValueManager dimensionGroupValueManager,
            IOrganizationRepository organizationRepository)
            : base(accountRepository, dimensionGroupValueRepository, currencyRepository, settlementRepository,
                 accountBalanceRepository, accountBalanceManager, dimensionGroupValueManager, organizationRepository)
        {
            _accountBalanceManager = accountBalanceManager;
            _settlementRepository = settlementRepository;
            _accountBalanceRepository = accountBalanceRepository;
        }

        public async Task<List<AccountBalanceReportDto>> GetData(ReportQueryBase query)
        {
            var result = new List<AccountBalanceReportDto>();

            var balances = await GetAccountBalancesAsync(query);

            if (balances.Count == 0)
                return result;

            result = await ConvertToBalanceReportDto(balances);

            result = HandleMulitPeriod(result);

            return result.OrderBy(x=>x.AccountCode).ToList();
        }

        #region
        private List<AccountBalanceReportDto> HandleMulitPeriod(List<AccountBalanceReportDto> balances)
        {
            //同一期就不处理了
            if (balances.Count == 0)
                return balances;

            var result = new List<AccountBalanceReportDto>();

            var groupByAccountId = balances.GroupBy(x => x.AccountId);

            foreach (IGrouping<Guid, AccountBalanceReportDto> info in groupByAccountId)
            {
                var accountId = info.Key;

                var groupByBalances = info.ToList();

                var minPeriod = groupByBalances.Min(x => x.Period);

                var maxPeriod = groupByBalances.Max(x => x.Period);

                var maxGroupByBalances = groupByBalances.Where(x => x.Period == maxPeriod);

                foreach (var balance in maxGroupByBalances)
                {
                    var minPeriodBalance = groupByBalances.FirstOrDefault(x => x.AccountId == accountId && x.CurrencyId == balance.CurrencyId && x.DimensionGroupValueId == balance.DimensionGroupValueId && x.Period == minPeriod);

                    var isMatch = minPeriodBalance != null;

                    //期初去最小期间的
                    balance.OpeningAmount = isMatch ? minPeriodBalance.OpeningAmount : null;
                    balance.OpeningAmountFr = isMatch ? minPeriodBalance.OpeningAmountFr : null;

                    //本期发生额算合计
                    var matchBalances = groupByBalances.Where(x => x.AccountId == accountId && x.CurrencyId == balance.CurrencyId && x.DimensionGroupValueId == balance.DimensionGroupValueId).ToList();

                    isMatch = matchBalances.Count > 0;

                    balance.DebitAmount = isMatch ? matchBalances.Where(x => x.DebitAmount.HasValue).Count() > 0 ? matchBalances.Where(x => x.DebitAmount.HasValue).Sum(x => x.DebitAmount) : null : null;
                    balance.DebitAmountFr = isMatch ? matchBalances.Where(x => x.DebitAmountFr.HasValue).Count() > 0 ? matchBalances.Sum(x => x.DebitAmountFr) : null : null;

                    balance.CreditAmount = isMatch ? matchBalances.Where(x => x.CreditAmount.HasValue).Count() > 0 ? matchBalances.Sum(x => x.CreditAmount) : null : null;
                    balance.CreditAmountFr = isMatch ? matchBalances.Where(x => x.CreditAmountFr.HasValue).Count() > 0 ? matchBalances.Sum(x => x.CreditAmountFr) : null : null;


                    //期末和本年累计就取最大期间的值
                    result.Add(balance);
                }
            }

            return result;
        } 
        #endregion
    }
}
